package com.github.panchitoboy.shiro.note;

import java.util.Timer;
import java.util.TimerTask;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import com.thinkgem.jeesite.common.utils.ClientInfoUtil;
import com.thinkgem.jeesite.common.utils.JedisUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 访问次数限制注解实现
 */
@Slf4j
@Aspect
@Component
public class RequestLimitContract {

    /**
     * 注解@before代表在请求发送到控制器之前会先来到这里执行相应的内容，within里面的书写表示写在控制器上方并且有对应注解的控制器会来到这里。
     * 在获得ip和对应的url之后将它作为一个key，存放到map中，假如map中已经存在了这个key，那么多产生一个时间处理器，当时间超过注解书写的单位时间之后又会将这个key从map中移走。
     * 假如访问的次数超过了限制，将会抛出异常说明访问次数过多
     *
     * 通过jedis计数
     *
     * @param joinPoint
     * @param limit
     * @throws RequestLimitException
     */
    @Before("@annotation(limit)")
    public void requestLimit(final JoinPoint joinPoint, RequestLimit limit) {
        try {
            Object[] args = joinPoint.getArgs();
            HttpServletRequest request = null;
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof HttpServletRequest) {
                    request = (HttpServletRequest) args[i];
                    break;
                }
            }
            if (request == null) {
                throw new RequestLimitException("方法中缺失HttpServletRequest参数");
            }
            //String ip = request.getLocalAddr();当用nginx等反向代理后，不能获取到真实的ip地址
            String ip = ClientInfoUtil.getIpAddr(request);
//            String url = request.getRequestURL().toString();
//            final String key = "req_limit_" .concat(url).concat(ip);
            final String key = "req_limit_" .concat(ip);
            if (JedisUtils.get(key) == null || Integer.parseInt(JedisUtils.get(key)) == 0) {
            	JedisUtils.set(key, "1", 0);
            } else {
            	JedisUtils.set(key, (Integer.parseInt(JedisUtils.get(key)) + 1)+"", 0);
            }
            int count = Integer.parseInt(JedisUtils.get(key));
            if (count > 0) {
                //创建一个定时器
                Timer timer = new Timer();
                TimerTask timerTask = new TimerTask() {
                    @Override
                    public void run() {
                    	JedisUtils.del(key);
                    }
                };
                //这个定时器设定在time规定的时间之后会执行上面的remove方法，也就是说在这个时间后它可以重新访问
                timer.schedule(timerTask, limit.time());
            }
            if (count > limit.count()) {
                throw new RequestLimitException();
            }
        } catch (RequestLimitException e) {
            throw e;
        } catch (Exception e) {
        }
    }
}